#pragma once
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <memory>
#include <functional>

#include "Socket.hpp"
#include "HttpService.hpp"

using namespace socket_ns;
using namespace Http_ns;

using service_io_t = std::function<std::string(std::string&)>;

class Server
{
public:
    Server(const uint16_t &port)
        : _port(port), _listen_sockfd(std::make_shared<TcpSocket>())
    {
    }
    ~Server()
    {}
    class ThreadData
    {
    public:
        ThreadData(SockPtr Td_sockfd,const InetAddr Td_addr, Server* Td_self)
            :_Td_sockfd(Td_sockfd), _Td_addr(Td_addr), _Td_self(Td_self)
        {}

    public:
        SockPtr _Td_sockfd;
        InetAddr _Td_addr;
        Server* _Td_self;
    };

    void Init(service_io_t service)
    {
        _listen_sockfd->BuildListenSocket(_port);
        _service = service;
    }

    void Start()
    {
        while (true)
        {
            // 接收从客户端发来的连接，得到用于通信的fd
            InetAddr client;
            SockPtr client_sockfd = _listen_sockfd->Accepter(&client);

            // version 2: 多线程方法，
            // 需要注意的是，对于线程，同进程一样，当线程结束时也需要主线程进行pthread_join()来回收线程资源
            // 不过对于多线程，是不需要主线程关闭文件描述符的，也不能关闭，因为线程之间的数据是共享的，如果关闭了
            // 那么子线程的client_sockfd也就关闭了。

            pthread_t tid;
            Server::ThreadData* td = new Server::ThreadData(client_sockfd, client, this);
            pthread_create(&tid, nullptr, Execute, td);

        }
    }

    static void* Execute(void* arg)
    {
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(arg);

        std::string requeststr;
        ssize_t n = td->_Td_sockfd->Recv(&requeststr); // 我们后面不做请求的分离，我们认为读到的是一个完整的请求 --- bug
        if (n > 0)
        {
            std::string responsestr = td->_Td_self->_service(requeststr);
            td->_Td_sockfd->Send(responsestr);
        }

        td->_Td_sockfd->Close();
        delete td;

        return nullptr;
    }

    void Close()
    {
       _listen_sockfd->Close();
    }


public:
    uint16_t _port;
    SockPtr _listen_sockfd;

    service_io_t _service;  // 将任务交由上层传递，实现解耦化
};
